#ifndef prs_Rule_H
#define prs_Rule_H

#include "prs_Attr.h"
#include "sntText.h"
#include "sntTextDouble.h"


namespace prs { 
/**************************************
///////////////////////////////////////////////////////////////////////////////
struct TRuleSetAttrValue;
struct TRuleFrmChildren;
struct TRuleSetNodeIdOptionally;
struct TRuleUseTemplate;
struct TRuleFrmString;
///////////////////////////////////////////////////////////////////////////////

struct TRuleParam
{
  snt::text::TContext &Context;
  svl::TVariant       &VParentNode;
  //
  TRuleSetAttrValue *RSetAttrValue;
  TRuleFrmChildren *RFrmChildren;
  TRuleSetNodeIdOptionally *RSetNodeIdOptionally;
  TRuleUseTemplate *RUseTemplate;
  TRuleFrmString *RFrmString;
  //
  TRuleParam(
    snt::text::TContext &context,
    svl::TVariant       &vParentNode
  )
  :Context(context)
  ,VParentNode(vParentNode)
  {
    RSetAttrValue = NULL;
    RFrmChildren = NULL;
    RSetNodeIdOptionally = NULL;
    RUseTemplate = NULL;
    RFrmString = NULL;
  }
};
*********************************/

///////////////////////////////////////////////////////////////////////////////

struct TRuleSetAttrValue : public snt::TRule
{
  TRuleSetAttrValue(
    snt::text::TContext &Context
  );

  //
  struct TFuncValueIdentParams
  {
    TAttr *Attr;
    svl::TString Ident;
    svl::TString OutError;
    //
    TFuncValueIdentParams() { Attr = NULL;}
  };
  typedef fastdelegate::FastDelegate<bool(TFuncValueIdentParams &Params)> TFuncValueIdent;

  template<class PObj,class PFunc> static TFuncValueIdent SetFuncValueIdent(PObj pObj,PFunc pFunc) {
    TFuncValueIdent F; F.bind(pObj,pFunc); return F;
  }
  //static TFuncValueIdent SetNullFuncValueIdent() {
  //  return TFuncValueIdent();
  //}


  struct TAttrs : public svl::TEnumSet
  {
    TAttrs &Add(const char *AttrName) {
      svl::TEnumSet::Add((char*)AttrName,0);
      return *this;
    }
  	
  	template<class PObj,class PFunc>
	  TAttrs &Add(const char *AttrName,PObj pObj,PFunc pFunc) { 
		  svl::TEnumSet::Add((char*)AttrName,0); 
		  if (pObj) {
			  TFuncValueIdent F; 
			  F.bind(pObj,pFunc);
			  fSet[Count()-1] = F;
		  }
		  return *this;
	  }
	  
	  TAttrs &Add(const char *AttrName,TFuncValueIdent F) { 
		  svl::TEnumSet::Add((char*)AttrName,0); 
  	  fSet[Count()-1] = F;
		  return *this;
	  }

	private:  
	  void CopyFrom(TAttrs &V){ 
		  svl::TEnumSet::CopyFrom(V);
		  memcpy(fSet,V.fSet,sizeof(fSet));
	  }
	  TFuncValueIdent fSet[50];
	  friend TRuleSetAttrValue;
  };
  //
  snt::TRule &New(
    svl::TVariant &VNode,
    TAttrs &Attrs,
    TFuncValueIdent F = TFuncValueIdent()
  );

  //
  snt::TRule &New(
    svl::TVariant &VNode,
    const char *Attr1,
    TFuncValueIdent F = TFuncValueIdent()
  ){
    TRule &R = this->New(VNode,F); 
    addAttr(R,Attr1);
    return R;
  }
  //
  snt::TRule &New(
    svl::TVariant &VNode,
    const char *Attr1,const char *Attr2,
    TFuncValueIdent F = TFuncValueIdent()
  ){
    TRule &R = this->New(VNode,F); 
    addAttr(R,Attr1); addAttr(R,Attr2); 
    return R;
  }
  //
  snt::TRule &New(
    svl::TVariant &VNode,
    const char *Attr1,const char *Attr2,const char *Attr3,
    TFuncValueIdent F = TFuncValueIdent()
  ){
    TRule &R = this->New(VNode,F); 
    addAttr(R,Attr1); addAttr(R,Attr2); addAttr(R,Attr3);
    return R;
  }

private:
  snt::TRule &New(svl::TVariant &VNode,TFuncValueIdent F) {
    TParam *P = new TParam;
      P->VNode = &VNode;
      P->funcValueIdent = F;
    TRule &R = snt::TRule::New();
      R.SetParams(P);
    return R;
  }
  TAttr *GetAttr();
  //
  void FGetEnumSetAttr(snt::text::TEnumSet::TFuncGetEnumSetParams &Params);
  bool FSetAttr       (snt::text::TEnumSet::TFuncDoEntryParams    &Params);
  //
  bool FSetValueString(snt::text::TString::TFuncClosureDoEntryParams &Params);
  bool FAddValueString(snt::text::TString::TFuncClosureDoEntryParams &Params);
  //
  bool FSetValueDateTime(snt::text::TNumber::TFuncClosureDoEntryParams &Params);
  //
  bool FSetValueDouble(sntText::TDouble::TFuncClosureDoEntryParams &Params);
  //
  bool FSetValueNumber(snt::text::TNumber  ::TFuncClosureDoEntryParams &Params);
  bool FSetValueTrue  (snt::text::TSequence::TFuncClosureDoEntryParams &Params);
  bool FSetValueFalse (snt::text::TSequence::TFuncClosureDoEntryParams &Params);
  //
  void FGetEnumSetEnum(snt::text::TEnumSet::TFuncGetEnumSetParams &Params);
  bool FSetValueEnum  (snt::text::TEnumSet::TFuncDoEntryParams    &Params);
  //
  bool FSetValueIdent (snt::text::TIdent::TFuncClosureDoEntryParams &Params);
  //
  struct TParam : public svl::TPointer
  {
    svl::TVariant *VNode;
    TAttrs Attrs;
    TFuncValueIdent funcValueIdent;
  };
  static TParam *getParams(snt::TRule &R) { return static_cast<TParam*>(R.GetParams());}
  static void addAttr(snt::TRule &R,const char *Attr) { getParams(R)->Attrs.Add(Attr);}
  //
  svl::TVariant vAttr,vEnString,vEnNumber,vEnEnum,vEnBool,vEnIdent,vEnDateTime,vEnDouble;
  svl::TVariant vDT1,vDT2;
  snt::TRule  RString, RDatetime, RDateTime;
  snt::TAlter AValue,ABool,AString;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////
}

#endif
